package com.xingyang.yutnori.model;

import java.util.ArrayList;
import java.util.List;

/**
 * Represents a playing piece in the Yut Nori game.
 * Each piece belongs to a player and can be moved around the board.
 * Pieces can also be stacked together.
 */
public class Piece {
    private Player owner;
    private int id;
    private int position;
    private int previousPosition; // Track previous position for special movement logic
    
    // Stack-related properties
    private Piece stackLeader;  // The piece that leads this stack (null if this is the leader)
    private List<Piece> stackedPieces;  // Pieces stacked on this piece (empty if none)
    
    /**
     * Constructs a new piece with the specified owner and ID.
     * 
     * @param owner The player who owns this piece
     * @param id The piece's ID (0-3)
     */
    public Piece(Player owner, int id) {
        this.owner = owner;
        this.id = id;
        this.position = -1;  // Start off the board
        this.previousPosition = -1; // Start with no previous position
        this.stackedPieces = new ArrayList<>();
    }
    
    /**
     * Gets the player who owns this piece.
     * 
     * @return The owner of this piece
     */
    public Player getOwner() {
        return owner;
    }
    
    /**
     * Gets the piece's ID.
     * 
     * @return The piece's ID
     */
    public int getId() {
        return id;
    }
    
    /**
     * Gets the piece's current position on the board.
     * -1 means the piece is still at home (not on the board).
     * 30 means the piece has reached the end.
     * 
     * @return The piece's position
     */
    public int getPosition() {
        return position;
    }
    
    /**
     * Gets the piece's previous position on the board.
     * 
     * @return The piece's previous position
     */
    public int getPreviousPosition() {
        return previousPosition;
    }
    
    /**
     * Sets the piece's position on the board.
     * 
     * @param position The new position
     */
    public void setPosition(int position) {
        this.previousPosition = this.position; // Save the current position as previous
        this.position = position;
        
        // Update stacked pieces' positions as well
        for (Piece piece : stackedPieces) {
            piece.previousPosition = piece.position; // Save previous position for stacked pieces too
            piece.position = position;
        }
    }
    
    /**
     * Checks if this piece has reached the end of the board.
     * 
     * @return True if the piece has reached the end, false otherwise
     */
    public boolean hasFinished() {
        return position == 30;
    }
    
    /**
     * Checks if this piece is stacked with other pieces.
     * 
     * @return True if this piece is part of a stack, false otherwise
     */
    public boolean isStacked() {
        return stackLeader != null;
    }
    
    /**
     * Checks if this piece has other pieces stacked on it.
     * 
     * @return True if this piece has stacked pieces, false otherwise
     */
    public boolean hasStackedPieces() {
        return !stackedPieces.isEmpty();
    }
    
    /**
     * Gets the piece that leads the stack containing this piece.
     * 
     * @return The stack leader, or null if this piece is the leader
     */
    public Piece getStackLeader() {
        return stackLeader;
    }
    
    /**
     * Gets the pieces stacked on this piece.
     * 
     * @return A list of stacked pieces
     */
    public List<Piece> getStackedPieces() {
        return stackedPieces;
    }
    
    /**
     * Stacks another piece on this piece.
     * 
     * @param piece The piece to stack
     */
    public void stackPiece(Piece piece) {
        // If this piece is part of a stack, add to the leader instead
        if (isStacked()) {
            stackLeader.stackPiece(piece);
            return;
        }
        
        // If the piece is already stacked elsewhere, unstack it first
        if (piece.isStacked()) {
            piece.getStackLeader().unstackPiece(piece);
        }
        
        // Stack the piece
        stackedPieces.add(piece);
        piece.stackLeader = this;
        piece.position = this.position;
        
        // If the piece has its own stacked pieces, transfer them
        if (piece.hasStackedPieces()) {
            List<Piece> transferPieces = new ArrayList<>(piece.stackedPieces);
            piece.stackedPieces.clear();
            
            for (Piece transferPiece : transferPieces) {
                stackPiece(transferPiece);
            }
        }
    }
    
    /**
     * Removes a piece from this stack.
     * 
     * @param piece The piece to remove
     * @return True if the piece was removed, false otherwise
     */
    public boolean unstackPiece(Piece piece) {
        if (stackedPieces.remove(piece)) {
            piece.stackLeader = null;
            return true;
        }
        return false;
    }
    
    /**
     * Clears all stacked pieces from this piece.
     */
    public void clearStackedPieces() {
        // Reset all stacked pieces
        for (Piece piece : stackedPieces) {
            piece.stackLeader = null;
        }
        stackedPieces.clear();
        
        // Reset this piece's stack leader
        stackLeader = null;
    }
    
    /**
     * Sets the piece's previous position directly.
     * This is useful for tracking movement history.
     * 
     * @param previousPosition The previous position to set
     */
    public void setPreviousPosition(int previousPosition) {
        this.previousPosition = previousPosition;
        
        // Update stacked pieces' previous positions as well
        for (Piece piece : stackedPieces) {
            piece.previousPosition = previousPosition;
        }
    }
    
    @Override
    public String toString() {
        return owner.getName() + " Piece " + (id + 1);
    }
} 